package com.real8.plusplayground.client;

import com.google.api.gwt.client.impl.ClientGoogleApiRequestTransport;
import com.google.api.gwt.client.impl.ClientOAuth2Login;
import com.google.api.gwt.services.plus.shared.Plus;
import com.google.api.gwt.services.plus.shared.Plus.PlusAuthScope;
import com.google.api.gwt.shared.GoogleApiRequestTransport;
import com.google.gwt.activity.shared.ActivityManager;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.core.client.GWT;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceHistoryHandler;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.Window;
import com.google.web.bindery.event.shared.EventBus;
import com.google.web.bindery.event.shared.SimpleEventBus;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.real8.plusplayground.client.activity.ActivityReadView;
import com.real8.plusplayground.client.activity.ActivityReadViewImpl;
import com.real8.plusplayground.client.menu.MenuPresenter;
import com.real8.plusplayground.client.menu.MenuView;
import com.real8.plusplayground.client.menu.MenuViewer;
import com.real8.plusplayground.client.person.PersonView;
import com.real8.plusplayground.client.person.PersonViewer;
import com.real8.plusplayground.client.shell.PlusPlaygroundShellView;
import com.real8.plusplayground.client.shell.PlusPlaygroundShellViewImpl;
import com.real8.plusplayground.client.statistics.StatisticsView;
import com.real8.plusplayground.client.statistics.StatisticsViewer;

public class ClientFactoryImpl implements ClientFactory {
	private static final String STORAGE_URL_ARG = "storage";

	private final Storage localStorage;

	private AppConstants appConstants = GWT.create(AppConstants.class);

	private final EventBus eventBus = new SimpleEventBus();

	private ActivityManager activityManager;
	private final PlaceController placeController = new PlaceController(
			eventBus);

	private final AppPlaceHistoryMapper historyMapper = GWT
			.create(AppPlaceHistoryMapper.class);
	private final PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(
			historyMapper);

	@SuppressWarnings("unused")
	private MenuPresenter menuPresenter;

	private Plus plus = null;

	private PlusPlaygroundShellView shellView;
	private MenuView menuView;
	private ActivityReadView activityReadView;
	private PersonView personReadView;
	private StatisticsView statisticsView;

	public ClientFactoryImpl() {
		// initialize local storage.
		String storageUrlValue = Window.Location.getParameter(STORAGE_URL_ARG);
		if (storageUrlValue == null || storageUrlValue.startsWith("t")) {
			localStorage = Storage.getLocalStorageIfSupported();
		} else {
			localStorage = null;
		}

		// left side menu
		// TODO put somewhere else?
		menuPresenter = new MenuPresenter(this);
		getShell().setMenu(getMenuView());
	}

	@Override
	public AppConstants getAppConstants() {
		return appConstants;
	}

	@Override
	public App getApp() {
		return new App(this, localStorage, eventBus, placeController,
				getActivityManager(), historyMapper, historyHandler, getShell());
	}

	@Override
	public EventBus getEventBus() {
		return eventBus;
	}

	@Override
	public PlaceController getPlaceController() {
		return placeController;
	}

	private ActivityMapper createActivityMapper() {
		return new AppActivityMapper(this);
	}

	private ActivityManager getActivityManager() {
		if (activityManager == null) {
			activityManager = new ActivityManager(createActivityMapper(),
					eventBus);
		}

		return activityManager;
	}

	@Override
	public void login(final Receiver<String> accessTokenReceiver) {
		new ClientOAuth2Login(getAppConstants().CLIENT_ID()).withScopes(
				PlusAuthScope.PLUS_ME).login(new Receiver<String>() {
			@Override
			public void onSuccess(String accessToken) {
				accessTokenReceiver.onSuccess(accessToken);
			}
		});
	}

	@Override
	public Plus getPlus() {
		return plus;
	}

	@Override
	public void createNewPlus(final Receiver<Plus> plusReceiver) {
		// create transport
		GoogleApiRequestTransport transport = new ClientGoogleApiRequestTransport();

		// initialize transport
		transport.setApplicationName(getAppConstants().APPLICATION_NAME())
				.setApiAccessKey(getAppConstants().API_KEY())
				.create(new Receiver<GoogleApiRequestTransport>() {
					@Override
					public void onSuccess(GoogleApiRequestTransport transport) {
						// create and initialize plus
						createAndInitializePlusRequestFactory(transport,
								plusReceiver);
					}
				});
	}

	private void createAndInitializePlusRequestFactory(
			GoogleApiRequestTransport transport, Receiver<Plus> plusReceiver) {
		// create
		plus = GWT.create(Plus.class);

		// initialize
		plus.initialize(getEventBus(), transport);

		// report success
		plusReceiver.onSuccess(plus);
	}

	@Override
	public void createNewPlus(String authorizationToken,
			final Receiver<Plus> plusReceiver) {
		// create transport
		GoogleApiRequestTransport transport = new ClientGoogleApiRequestTransport();

		// initialize transport
		transport.setAccessToken(authorizationToken)
				.setApplicationName(getAppConstants().APPLICATION_NAME())
				.create(new Receiver<GoogleApiRequestTransport>() {
					@Override
					public void onSuccess(GoogleApiRequestTransport transport) {
						// create and initialize plus
						createAndInitializePlusRequestFactory(transport,
								plusReceiver);
					}
				});
	}

	@Override
	public PlusPlaygroundShellView getShell() {
		if (shellView == null) {
			shellView = new PlusPlaygroundShellViewImpl();
		}

		return shellView;
	}

	@Override
	public MenuView getMenuView() {
		if (menuView == null) {
			menuView = new MenuViewer();
		}

		return menuView;
	}

	@Override
	public ActivityReadView getActivityReadView() {
		if (activityReadView == null) {
			activityReadView = new ActivityReadViewImpl();
		}

		return activityReadView;
	}

	@Override
	public PersonView getPersonView() {
		if (personReadView == null) {
			personReadView = new PersonViewer();
		}

		return personReadView;
	}

	@Override
	public StatisticsView getStatisticsView() {
		if (statisticsView == null) {
			statisticsView = new StatisticsViewer();
		}

		return statisticsView;
	}
}
